Fiber
为什么要用Fiber?
在之前的版本中，如果你拥有一个很复杂的复合组件，然后改动了最上层组件的 state，那么调用栈可能会
很长。调用栈过长，再加上中间进行了复杂的操作，就可能导致长时间阻塞主线程，带来不好的用户体验。
Fiber 就是为了解决该问题而生。

Fiber是什么？
Fiber 本质上是一个虚拟的堆栈帧，新的调度器会按照优先级自由调度这些帧，从而将之前的同步渲染改成
了异步渲染，在不影响体验的情况下去分段计算更新。

核心理念：
Fiber 其实可以算是一种编程思想，在其它语言中也有许多应用(Ruby Fiber)。核心思想是 任务拆分和协同，
主动把执行权交给主线程，使主线程有时间空挡处理其他高优先级任务。当遇到进程阻塞的问题时，任务分割、
异步调用 和 缓存策略 是三个显著的解决思路。

异步渲染，现在渲染有两个阶段：
①reconciliation （前者过程是可以打断的）
    reconciliation阶段: Reconciliation 阶段会执行的生命周期函数就可能会出现调用多次的情况，从而引起 Bug
    ①componentWillMount  //即将过时，应该避免使用
    ②componentWillReceiveProps  -->getDerivedStateFromProps //会在初始化和 update 时被调用
    注释：每次渲染前触发此方法，初始挂载及后续更新时都会被调用。
    UNSAFE_componentWillReceiveProps 形成对比，后者仅在父组件
    重新渲染时触发，而不是在内部调用 setState 时
    ③shouldComponentUpdate
    ④componentWillUpdate --> getSnapshotBeforeUpdate //update 后 DOM 更新前被调用，用于读取最新的 DOM 数据
    注释：除了 shouldComponentUpdate 以外，其他都应该避免去使用
②commit （后者不能暂停，会一直更新界面直到完成）
    Commit 阶段：
        ①componentDidMount
        ②componentDidUpdate
        ③componentWillUnmount

生命周期：
①挂载
    constructor() //初始化 state
    static getDerivedStateFromProps(props, state) //需要根据 props 更新 state 时
    render()
    componentDidMount() //数据的请求、事件监听
②更新
    static getDerivedStateFromProps() //返回一个对象来更新 state
    shouldComponentUpdate(nextProps, nextState) //首次渲染或使用 forceUpdate() 时不会调用该方法
    render()
    getSnapshotBeforeUpdate(prevProps, prevState) //返回值将作为参数传递给 componentDidUpdate()
    componentDidUpdate(prevProps, prevState, snapshot) //可在条件语句里调用 setState()，否则会导致死循环
③卸载
    componentWillUnmount() //解绑事件
④错误处理：当渲染过程，生命周期，或子组件的构造函数中抛出错误时
    static getDerivedStateFromError(error)
    componentDidCatch(err,info)

其他API
①setState()
首先 setState 的调用并不会马上引起 state 的改变，并且如果你一次调用了多个 setState ，那么结果
可能并不如你期待的一样
①setState 是个异步 API，只有同步代码运行完毕才会执行
注释：对组件 state 的更改排入队列，并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件
异步原因：setState 可能会导致 DOM 的重绘，如果调用一次就马上去进行重绘，那么调用多次就会造成不必要的性能损失。
设计成异步的话，就可以将多次调用放入一个队列中，在恰当的时候统一进行更新过程。
②多次调用会合并为一次，只有当更新结束后 state 才会改变
解决：updater 函数,返回值会与 state 进行浅合并。
this.setState((state, props) => { //state 和 props 都保证为最新
    return {counter: state.counter + props.step};
  });
注释：
①第一个参数可以是对象也可以是函数，更新会被合并,是浅合并
②setState() 的第二个参数为可选的回调函数，它将在 setState 完成合并并重新渲染组件后执行。通常，
我们建议使用 componentDidUpdate() 来代替此方式。

②forceUpdate()
当组件的 state 或 props 发生变化时，组件将重新渲染。如果 render() 方法依赖于其他数据，则可以
调用 forceUpdate() 强制让组件重新渲染。
注意：此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法，包括 
shouldComponentUpdate() 方法。

性能优化
shouldComponentUpdate()仅作为性能优化的方式而存在
①可以将 this.props 与 nextProps 以及 this.state 与nextState 进行比较，并返回 false 
以告知 React 可以跳过更新。请注意，返回 false 并不会阻止子组件在 state 更改时重新渲染。
注释：不推荐进行深层比较或使用 JSON.stringify()。这样非常影响效率，且会损害性能。
②可以直接使用 PureComponent，底层就是实现了浅比较 state，并减少了跳过必要更新的可能性。
注释：16.6.0 版本函数组件可以使用 React.memo 来实现相同的功能。
③可以通过 immutable 或者 immer 这些库来生成不可变对象。这类库对于操作大规模的数据来说会提升
不错的性能，并且一旦改变数据就会生成一个新的对象，对比前后 state 是否一致也就方便多了。
注意：后续版本，React 可能会将 shouldComponentUpdate 视为提示而不是严格的指令，并且，当返回 
false 时，仍可能导致组件重新渲染。

纯函数:不会试图改变它们的输入，并且对于同样的输入,始终可以得到相同的结果,React 组件都必须是纯函数，
并禁止修改其自身 props

函数组件和无状态组件？

无状态(没有state)组件（简写）创建：
	const 组件名=(props)=>(jsx)
	const 组件名=props=>jsx
	const 组件名=(props)=>{
		let xx=props.xx
		return html
	}

    无状态组件特点：
        不能访问this对象(this.ref,this.state  ... )
        只能访问props
        无需实例化，渲染性能高
        this.方法/钩子（生命周期)  也不需要

通信：
    ①跨多层次组件通信:16.3 以上版本可以使用 Context API
    何时用：Context 可以让我们无须明确地传遍每一个组件，就能将值深入传递进组件树
    例子：
    const ThemeContext = React.createContext('light'); //创建一个 Context 对象

    class App extends React.Component {
        render() {
          // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
          // 无论多深，任何组件都能读取这个值。
          // 在这个例子中，我们将 “dark” 作为当前的值传递下去。
          return (
            <ThemeContext.Provider value="dark"> //每个 Context 对象都会返回一个 Provider React 组件
              <Toolbar />
            </ThemeContext.Provider> //Provider 接收一个 value 属性，传递给消费组件
          );
        }
      }

    function Toolbar(props) {// 中间的组件再也不必指明往下传递 theme 了。
        return (
            <div>
            <ThemedButton />
            </div>
        );
    }

    class ThemedButton extends React.Component {
        // 指定 contextType 读取当前的 theme context。
        // React 会往上找到最近的 theme Provider，然后使用它的值。
        // 在这个例子中，当前的 theme 值为 “dark”。
        static contextType = ThemeContext;
        render() {//使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它
            return <Button theme={this.context} />;
            return (
                <ThemeContext.Consumer> //注意：需要函数作为子元素
                    <Button theme={value => value} /> /* 基于 context 值进行渲染*/
                </ThemeContext.Consumer>
            )
        }

    }
    //此组件可以让你在函数式组件中可以订阅 context
    function ThemeTogglerButton() {
        // Theme Toggler 按钮不仅仅只获取 theme 值，
        // 它也从 context 中获取到一个 toggleTheme 函数
        return (
          <ThemeContext.Consumer>
            {({theme, toggleTheme}) => (
              <button
                onClick={toggleTheme}
                style={{backgroundColor: theme.background}}>
                Toggle Theme
              </button>
            )}
          </ThemeContext.Consumer>
        );
      }

    ②Redux： flux(思想)可以同一个地方查询状态，改变状态，传播状态
    何时用：
        中大项目,组件状态需要共享，在任何地方都可以拿到，组件需要改变全局状态，一个组件需要
        改变另外一个组件的状态
    思维：
	    在顶层组件创建store(状态),其他底层组件共享这个store(状态)
    数据流动：
        component->action->reducer->state->component
        component: 展示结果(含处理结果代码)
        action: 动作转发,异步请求， store.dispatch发送action 给 reducer
        reducer: 业务处理逻辑,返回(return)新state
        state:	状态收集，更新内部state状态，更新订阅(store.subscribe)state的组件（component）

        通过store.dispatch发送action 给 reducer
        在组件内部 通过 store.getState() 抓state状态  特点 只抓一次
                store.subscribe() 订阅  数据更新，会触发
                getState放在subscribe内部
    操作流程：
	1. {createStore} from 'redux'
	2. 生成默认state defaultState={}
	3.	创建reducer 
		const reducer = (state=defaultState,action)=>{
			let {type,payload}=action
			swtich type
				case XXXXX
				更新copy后的state  Object.assign(空,老,新)
			default:
				return state
		}
	4. 创建store对象
		store = createStore(reducer,defaultState)

	5. store传递给组件
		<组件名 store={store}/>

	6. 更新，状态获取
		组件内部:	this.props.store== store
			this.props.store.dispatch({type:xxx,payload:ooo}) 发送action给reducer
			this.props.store.subscribe(回调)  订阅 state  更新state时触发
			this.props.store.getState() 获取状态，执行一次

    react-redux
	基于redux思想,专门为react而生

    思想:  容器组件, UI组件
        App: 拿到store,修改、获取store
        store:外面
        index.js:
        import {Provider,connect} from react-redux
        <Provider store={store}>
            <容器组件/>
        </Provider>


事件机制：
    react事件机制：
    JSX 上写的事件并没有绑定在对应的真实 DOM 上，而是通过事件代理的方式，将所有的事件都统一绑定
    在了 document 上。这样的方式不仅减少了内存消耗，还能在组件挂载销毁时统一订阅和移除事件。

    注意：冒泡到 document 上的事件也不是原生浏览器事件，而是 React 自己实现的合成事件。因此我
    们如果不想要事件冒泡的话，调用 event.stopPropagation 是无效的，而应该调用 event.preventDefault。

    合成事件的优点：
    ①合成事件首先抹平了浏览器之间的兼容问题，另外这是一个跨浏览器原生事件包装器，赋予了跨浏览器开发的能力
    ②合成事件有一个事件池专门来管理它们的创建和销毁，当事件需要被使用时，就会从池子中复用对象，
    事件回调结束后，就会销毁事件对象上的属性，从而便于下次复用事件对象。

    对比：
    对于原生浏览器事件来说，浏览器会给监听器创建一个事件对象。如果你有很多的事件监听，那么就需要分配
    很多的事件对象，造成高额的内存分配问题。

HOC 是什么？相比 mixins 有什么优点？
HOC(高阶组件):参数为组件，返回值为新组件的函数
我们实现一个函数，传入一个组件，然后在函数内部再实现一个函数去扩展传入的组件，最后返回一个新的组件，
作用就是为了更好的复用代码。

HOC 和 Vue 中的 mixins 作用是一致的。使用 class 的方式创建组件以后，mixins 的方式就不能使用了
原因：
①隐含了一些依赖，比如我在组件中写了某个 state 并且在 mixin 中使用了，就这存在了一个依赖关系。
万一下次别人要移除它，就得去 mixin 中查找依赖
②多个 mixin 中可能存在相同命名的函数，同时代码组件中也不能出现相同命名的函数，否则就是重写了，
其实我一直觉得命名真的是一件麻烦事。
③雪球效应，虽然我一个组件还是使用着同一个 mixin，但是一个 mixin 会被多个组件使用，可能会存在
需求使得 mixin 修改原本的函数或者新增更多的函数，这样可能就会产生一个维护成本

HOC 解决了这些问题，并且它们达成的效果也是一致的，同时也更加的政治正确（毕竟更加函数式了）
应用：
    ①性能监控，包裹组件的生命周期，进行统一埋点
    ②权限控制，通过抽象逻辑，统一对页面进行权限判断，按不同的条件进行页面渲染
    ③提取状态: 可以通过 props 将被包裹组件中的 state 依赖外层，例如用于转换受控组件

ssr

